package com.ts.enterprise.common.interceptor;


import com.ts.enterprise.common.annotation.LoginBasicRequired;
import com.ts.enterprise.common.annotation.LoginRequired;
import com.ts.enterprise.common.consts.Constant;
import com.ts.enterprise.common.query.LoginUser;
import com.ts.enterprise.common.utils.JwtUtil;
import com.ts.enterprise.common.utils.RedisUtil;
import com.ts.enterprise.common.utils.SpringContextUtil;
import com.ts.enterprise.enums.PlatformEnum;
import com.ts.enterprise.exception.BusinessException;
import com.ts.enterprise.exception.ExceptionEnum;
import com.ts.enterprise.module.user.service.LoginService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @Author Administrator
 * @Date 2021/10/19 10:37
 * @Description
 */
@Slf4j
public class AuthInterceptor implements HandlerInterceptor {

    public static ThreadLocal<LoginUser> user = new ThreadLocal<>();

    private final int thousand = 1000;


    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (handler instanceof ResourceHttpRequestHandler) {
            //如果静态资源，不拦截
            return true;
        }
        HandlerMethod hm = (HandlerMethod) handler;
        LoginRequired loginRequired = hm.getMethodAnnotation(LoginRequired.class);
        LoginBasicRequired basicRequired = hm.getMethodAnnotation(LoginBasicRequired.class);
        if (null != loginRequired && null != basicRequired) {
            throw new BusinessException(ExceptionEnum.LOGIN_REQUIRED_PARAM_EXCEPTION);
        }
        String token = request.getHeader(Constant.TOKEN_HEADER);
        if (StringUtils.isBlank(token) && (null != loginRequired || null != basicRequired)) {
            throw new BusinessException(ExceptionEnum.UNAUTHENTICATED_EXCEPTION);
        }
        LoginUser user = new LoginUser();
        if (StringUtils.isNotBlank(token)) {
            if (null != loginRequired) {
                user = JwtUtil.decodeToUser(token);
                checkPermission(hm, user, request.getRequestURI());
                checkTokenExpiration(user.getTokenKey());
                AuthInterceptor.user.set(user);
            }
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }


    private void checkUserInfo(LoginUser loginUser) {
    }


    private void checkPermission(HandlerMethod hm, LoginUser user, String requestURI) {
        //方法需要的权限字符串
        String platform = user.getPlatform();
        PlatformEnum platformEnum = PlatformEnum.getName(platform);
        if (!requestURI.contains(platformEnum.getDesc()) && !requestURI.contains(Constant.API_COMMON)) {
            throw new BusinessException(ExceptionEnum.UNAUTHORIZED_EXCEPTION);
        }
    }

    private void checkTokenExpiration(String tokenKey) {
        String exp = RedisUtil.get(tokenKey);
        if (StringUtils.isNotBlank(exp)) {
            long parseLong = Long.parseLong(exp);
            if (parseLong - System.currentTimeMillis() / thousand < Constant.TOKEN_EXPIRATION_REFRESH) {
                LoginService loginService = SpringContextUtil.getBean(LoginService.class);
                loginService.setRedisToken(tokenKey, parseLong + Constant.TOKEN_EXPIRATION_REFRESH);
            }
        } else {
            log.info("token失效:{}", tokenKey);
            throw new BusinessException(ExceptionEnum.TOKEN_EXPIRED_EXCEPTION);
        }
    }

}
